package com.wanfajie.smsdistribute.ui.template_editor.widget

import android.content.Context
import android.text.Spanned
import android.util.AttributeSet
import android.view.KeyEvent
import android.view.View
import android.view.View.OnClickListener
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import android.view.inputmethod.InputConnectionWrapper
import android.widget.EditText
import com.wanfajie.smsdistribute.ui.template_editor.PlaceholderSpan

class TemplateEditView(ctx: Context, attrs: AttributeSet? = null) : EditText(ctx, attrs) {

    companion object {

        @JvmStatic
        private val DELETE_FIRST = setOf(
                android.R.id.paste,
                android.R.id.pasteAsPlainText,
                android.R.id.replaceText)
    }

    private inner class MyInputConnectionWrapper(target: InputConnection): InputConnectionWrapper(target, false) {

        override fun commitText(text: CharSequence?, newCursorPosition: Int): Boolean {
            setSelectionSafely()
            return super.commitText(text, newCursorPosition)
        }

        override fun sendKeyEvent(event: KeyEvent?): Boolean {

            when (event?.keyCode) {
                KeyEvent.KEYCODE_DEL -> {
                    if (event.action == KeyEvent.ACTION_UP) {
                        val text = text
                        val currStart = selectionStart
                        val currEnd = selectionEnd

                        if (currStart == currEnd) {
                            var deleted = false
                            text.getSpans(0, currEnd, PlaceholderSpan::class.java).forEach {
                                val (s, e) = getPlaceholderPos(it)

                                if (currStart in s+1..e) {
                                    text.delete(s, e)
                                    deleted = true
                                }
                            }

                            // 没有Span被删除时删除一个字符
                            if (!deleted) {
                                val delStart = currStart - 1

                                if (delStart >= 0)
                                    text.delete(delStart, currStart)
                            }
                        } else {
                            setSelectionSafely()
                            text.delete(selectionStart, selectionEnd)
                        }

                        return true
                    } else if (event.action == KeyEvent.ACTION_DOWN) {
                        return true
                    }
                }
                KeyEvent.KEYCODE_ENTER,
                KeyEvent.KEYCODE_NUMPAD_ENTER -> {
                    setSelectionSafely()
                }
                // TODO: KEYCODE_FORWARD_DEL
            }

            return super.sendKeyEvent(event)
        }
    }

    init {
        super.setOnClickListener { view ->
            val cursorPos = selectionStart

            getPlaceholders().forEach {
                val (t, start, end) = it

                if (cursorPos in start..end) {
                    val leftDis = cursorPos - start
                    val rightDis = end - cursorPos

                    if (leftDis < rightDis) {
                        setSelection(start)
                    } else {
                        setSelection(end)
                    }

                    t.onClick(this)
                    t.onSpanClick(this, t, text.substring(start, end), start)
                }
            }

            mOnClickListener?.onClick(view)
        }
    }

    private var mOnClickListener: OnClickListener? = null

    override fun setSelection(index: Int) {
        setSelectionSafely(index, index)
    }

    override fun setSelection(start: Int, stop: Int) {
        setSelectionSafely(start, stop)
    }

    private fun setSelectionSafely(start: Int? = null, stop: Int? = null) {
        var posStart = start ?: selectionStart
        var posStop = stop ?: selectionEnd
        getPlaceholders().forEach {
            val (_, s, e) = it
            val (first, second) = shiftCursorPos(s, e, posStart, posStop)
            posStart = first
            posStop = second
        }

        super.setSelection(posStart, posStop)
    }

    private fun shiftCursorPos(s: Int, e: Int, currStart: Int? = null, currEnd: Int? = null): Pair<Int, Int> {
        var cursorStart = currStart ?: selectionStart
        var cursorEnd = currEnd ?: selectionEnd
        val range = s+1 until e

        if (cursorStart !in range && cursorEnd !in range) {
            return cursorStart to cursorEnd
        }

        if (cursorStart == cursorEnd) {
            val leftDis = cursorStart - s
            val rightDis = e - cursorStart

            if (leftDis < rightDis) {
                cursorStart = s
                cursorEnd = s
            } else {
                cursorStart = e
                cursorEnd = e
            }
        } else {
            cursorStart = if (cursorStart in range) s else cursorStart
            cursorEnd = if (cursorEnd in range) e else cursorEnd
        }

        return cursorStart to cursorEnd
    }

    fun getPlaceholders(): Sequence<Triple<PlaceholderSpan, Int, Int>> {
        val text = text
        return text.getSpans(0, text.length, PlaceholderSpan::class.java).asSequence().map {
            val s = text.getSpanStart(it)
            val e = text.getSpanEnd(it)
            Triple(it, s, e)
        }
    }

    fun getPlaceholderStr(): List<Triple<String, Int, Int>> {
        val text = text
        return text.getSpans(0, text.length, PlaceholderSpan::class.java).map {
            val s = text.getSpanStart(it)
            val e = text.getSpanEnd(it)
            Triple(text.substring(s, e), s, e)
        }
    }

    private fun getPlaceholderPos(placeholder: PlaceholderSpan): Pair<Int, Int> {
        return text.getSpanStart(placeholder) to text.getSpanEnd(placeholder)
    }

    override fun onCreateInputConnection(outAttrs: EditorInfo?): InputConnection? {
        val inputConnection = super.onCreateInputConnection(outAttrs) ?: return null

        return MyInputConnectionWrapper(inputConnection)
    }

    override fun onTextContextMenuItem(id: Int): Boolean {
        when (id) {
            android.R.id.cut -> setSelectionSafely()
            in DELETE_FIRST -> {
                setSelectionSafely()
            }
        }
        return super.onTextContextMenuItem(id)
    }

    override fun setOnClickListener(l: OnClickListener?) {
        mOnClickListener = l
    }

    fun setOnClickListener(l: (v: View) -> Unit) {
        setOnClickListener(OnClickListener(l))
    }

    fun createPlaceholder(tag: CharSequence, factory: () -> PlaceholderSpan) {
        val text = text
        setSelectionSafely()
        val start = selectionStart
        val end = selectionEnd

        if (start == end) {
            text.insert(start, tag)
        } else {
            text.replace(start, end, tag)
        }

        val span = factory.invoke()
        text.setSpan(span, start, start + tag.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
    }
}